﻿using Mall.Repository.Repository;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Mall.Repository.RepositoryProgram
{
    internal class MemberExpressionToSql : BaseExpressionToSql<MemberExpression>
    {
        private string GetTableName(string s)
        {
            return ExpressionHelper.GetTableName(s);
        }
        private static object GetValue(MemberExpression expr)
        {
            FieldInfo fieldInfo = expr.Member as FieldInfo;
            if (fieldInfo != null)
            {
                return fieldInfo.GetValue(((ConstantExpression)expr.Expression).Value);
            }

            return ((PropertyInfo)expr.Member).GetValue(((ConstantExpression)expr.Expression).Value, null);
        }

        private SqlBuilder AggregateFunctionParser(MemberExpression expression, SqlBuilder sqlBuilder, string operation)
        {
            string text = GetTableName(expression.Expression.Type.Name);
            string text2 = expression.Member.Name;
            sqlBuilder.SetTableAlias(text);
            string tableAlias = sqlBuilder.GetTableAlias(text);
            if (!string.IsNullOrWhiteSpace(tableAlias))
            {
                text = text + " " + tableAlias;
                text2 = tableAlias + "." + text2;
            }

            sqlBuilder.AppendFormat("select {0}({1}) from {2}", operation, text2, text);
            return sqlBuilder;
        }

        protected override SqlBuilder Select(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            sqlBuilder.SetTableAlias(GetTableName(expression.Expression.Type.Name));
            string text = sqlBuilder.GetTableAlias(GetTableName(expression.Expression.Type.Name));
            if (!string.IsNullOrWhiteSpace(text))
            {
                text += ".";
            }

            sqlBuilder.SelectFields.Add(text + expression.Member.Name);
            return sqlBuilder;
        }

        protected override SqlBuilder Join(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            sqlBuilder.SetTableAlias(GetTableName(expression.Expression.Type.Name));
            string text = sqlBuilder.GetTableAlias(GetTableName(expression.Expression.Type.Name));
            if (!string.IsNullOrWhiteSpace(text))
            {
                text += ".";
            }

            sqlBuilder += " " + text + expression.Member.Name;
            return sqlBuilder;
        }

        protected override SqlBuilder Where(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            if (expression.Expression.NodeType == ExpressionType.Constant)
            {
                object value = GetValue(expression);
                sqlBuilder.AddDbParameter(value);
            }
            else if (expression.Expression.NodeType == ExpressionType.Parameter)
            {
                sqlBuilder.SetTableAlias(GetTableName(expression.Expression.Type.Name));
                string text = sqlBuilder.GetTableAlias(GetTableName(expression.Expression.Type.Name));
                if (!string.IsNullOrWhiteSpace(text))
                {
                    text += ".";
                }

                sqlBuilder += " " + text + expression.Member.Name;
            }

            return sqlBuilder;
        }

        protected override SqlBuilder In(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            FieldInfo fieldInfo = expression.Member as FieldInfo;
            if (fieldInfo != null)
            {
                object value = fieldInfo.GetValue(((ConstantExpression)expression.Expression).Value);
                if (value != null)
                {
                    string text = "";
                    foreach (object item in value as IEnumerable)
                    {
                        text = ((!(fieldInfo.FieldType.Name == "String[]")) ? ((!fieldInfo.FieldType.GetTypeInfo().IsEnum) ? (text + $",{item}") : (text + $",{(int)item}")) : (text + $",'{item}'"));
                    }

                    if (text.Length > 0)
                    {
                        text = text.Remove(0, 1);
                        text = $"({text})";
                        sqlBuilder += text;
                    }
                }
            }

            return sqlBuilder;
        }

        protected override SqlBuilder GroupBy(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            sqlBuilder.SetTableAlias(GetTableName(expression.Expression.Type.Name));
            sqlBuilder += sqlBuilder.GetTableAlias(GetTableName(expression.Expression.Type.Name)) + "." + expression.Member.Name;
            return sqlBuilder;
        }

        protected override SqlBuilder OrderBy(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            sqlBuilder.SetTableAlias(GetTableName(expression.Expression.Type.Name));
            sqlBuilder += sqlBuilder.GetTableAlias(GetTableName(expression.Expression.Type.Name)) + "." + expression.Member.Name;
            return sqlBuilder;
        }

        protected override SqlBuilder Max(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            return AggregateFunctionParser(expression, sqlBuilder, "max");
        }

        protected override SqlBuilder Min(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            return AggregateFunctionParser(expression, sqlBuilder, "min");
        }

        protected override SqlBuilder Avg(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            return AggregateFunctionParser(expression, sqlBuilder, "avg");
        }

        protected override SqlBuilder Count(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            return AggregateFunctionParser(expression, sqlBuilder, "count");
        }

        protected override SqlBuilder Sum(MemberExpression expression, SqlBuilder sqlBuilder)
        {
            return AggregateFunctionParser(expression, sqlBuilder, "sum");
        }
    }
}
